﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace CPF_experement
{
    class Trevor
    {
        bool diagonal;
        LinkedList<Trevor_Group> allGroups;
        public static int expanded;
        public static int generated;
        public static int totalTime;
        public int max_group;
        public int min_group;

        public Trevor(AgentState[] allAgentsState, bool diagonal)
        {
            expanded = 0;
            generated = 0;
            totalTime = 0;
            max_group = 0;
            min_group = allAgentsState.Length;
            this.diagonal = diagonal;
            this.allGroups = new LinkedList<Trevor_Group>();
            foreach (AgentState start in allAgentsState)
            {
                AgentState[] temp=new AgentState[1];
                temp[0] = start;
                this.allGroups.AddFirst(new Trevor_Group(temp, diagonal));
            }

        }
        public void solve()
        {
            bool stop;
            LinkedListNode<Trevor_Group> tempA = allGroups.First;
            LinkedListNode<Trevor_Group> tempB;
            while (tempA!=null)
            {
                tempA.Value.solve();
                if (tempA.Value.solution == null)
                {
                    Console.WriteLine("Expanded - " + expanded);
                    Console.WriteLine("Generated - " + generated);
                    if (totalTime==-2)
                    {
                        Console.WriteLine("Out of time");
                        return;
                    }
                    Console.WriteLine("No solution found");
                    return;
                }
                tempB = allGroups.First;
                stop = false;
                while (tempB!=tempA && !stop)
                {
                    if (tempA.Value.isColaiding(tempB.Value))
                    {
                        tempA.Value.join(tempB.Value);
                        allGroups.Remove(tempB);
                        stop = true;
                    }
                    tempB = tempB.Next;
                }
                if (!stop)
                    tempA = tempA.Next;
            }
            foreach (Trevor_Group ans in allGroups)
            {
                if (ans.allAgentsState.Length>max_group)
                {
                    max_group = ans.allAgentsState.Length;
                }
                if (ans.allAgentsState.Length < min_group)
                {
                    min_group = ans.allAgentsState.Length;
                }
                totalTime += ans.solution.totalTime_G;
               //printSolution(ans.solution);
            }
            print();

        }
        private void printSolution(Travor_WorldState end)
        {
            int step = 0;
            Console.WriteLine("solution back to front");
            Console.WriteLine("------------------------------\n");
            while (end != null)
            {
                Console.WriteLine("step " + step);
                Console.WriteLine(end.ToString());
                step++;
                end = end.prevStep;
            }
        }
        private void print()
        {
            Console.WriteLine("Expanded - " + expanded);
            Console.WriteLine("Generated - " + generated);
            Console.WriteLine("Total cost - " + totalTime);
        }
    }
    class Trevor_Group
    {
        bool diagonal;
        LinkedList<LinkedList<Point>> reservations;
        public AgentState[] allAgentsState;
        public Travor_WorldState solution;


        public Trevor_Group(AgentState[] allAgentsState, bool diagonal)
        {
            this.diagonal = diagonal;
            this.allAgentsState = allAgentsState;
        }

        public void solve()
        {
            reservations = new LinkedList<LinkedList<Point>>();
            Trevor_A_star.init_Travor_A_star(allAgentsState, diagonal);
            solution = Trevor_A_star.solve();
            Travor_WorldState temp = solution;
            while (temp!=null)
            {
                reservations.AddFirst(temp.getAllPoints());
                temp = temp.prevStep;
            }
        }

        public bool isColaiding(Trevor_Group other)
        {
            LinkedList<LinkedList<Point>> first = this.reservations;
            LinkedList<LinkedList<Point>> second = other.reservations;
            if (second.Count>first.Count)
            {
                first = second;
                second = this.reservations;
            }
            Point check;
            LinkedListNode<LinkedList<Point>> node_First = first.First;
            LinkedListNode<LinkedList<Point>> node_Second = second.First;
            while (node_First!=null)
            {
                foreach (Point temp in node_First.Value)
                {
                    if (node_Second.Value.Contains(temp.getColaidingPoint()) )
                        return true;
                    check = new Point(temp);
                    check.direction = -1;
                    if (node_Second.Value.Contains(check))
                        return true;
                }
                node_First = node_First.Next;
                if (node_Second.Next != null)
                    node_Second = node_Second.Next;
            }
            return false;
        }

        public Trevor_Group join(Trevor_Group other)
        {
            AgentState[] temp = new AgentState[allAgentsState.Length + other.allAgentsState.Length];
            int i;
            for ( i = 0; i < allAgentsState.Length; i++)
            {
                temp[i] = allAgentsState[i];
            }
            for (int j = 0; j < other.allAgentsState.Length; j++)
            {
                temp[i + j] = other.allAgentsState[j];
            }
            allAgentsState = temp;
            return this;
        }
    }
}
